use ggez;
use ggez::event;
use ggez::graphics;
use ggez::nalgebra as na;
use rand::{thread_rng, Rng};
use std::collections::HashMap;
use std::thread::sleep;
use std::time;

const WIDTH: f32 = 500.0;
const HEIGHT: f32 = 500.0;

const GRID_X: f32 = WIDTH / 10.0;
const GRID_Y: f32 = HEIGHT / 10.0;



fn alive_gen() ->  HashMap<[i32; 2], i32> {
    let mut alive = HashMap::new();
    let mut rng = thread_rng();

    let mut x = 0;
    let mut y = 0;
    while x < GRID_X as i32 {
        while y < GRID_Y as i32{
            if rng.gen_bool(0.5) == true {
                alive.insert([x,y], 0);
            }
            y += 1;
        }
        y = 0;
        x += 1;
    }
    alive
}

fn count_neighbors(list: HashMap<[i32; 2], i32>) -> HashMap<[i32; 2], i32> {
    let new_list = list;
    let mut new_new_list = new_list.clone();
    let mut x = 0;
    let mut y = 0;
    
    while x < GRID_X.round() as i32{
        while y < GRID_Y.round() as i32{
            let mut total =0;
            if new_list.contains_key(&[(x - 1), (y - 1)]) {
                total += 1;

            }if new_list.contains_key(&[(x - 1), (y - 0)]) {
                total += 1;

            }if new_list.contains_key(&[(x - 0), (y - 1)]) {
                total += 1;

            }if new_list.contains_key(&[(x + 1), (y + 1)]) {
                total += 1;

            }if new_list.contains_key(&[(x + 1), (y + 0)]) {
                total += 1;

            }if new_list.contains_key(&[(x + 0), (y + 1)]) {
                total += 1;

            }if new_list.contains_key(&[(x + 1), (y - 1)]) {
                total += 1;

            }if new_list.contains_key(&[(x - 1), (y + 1)]) {
                total += 1;
            }
            if total < 2 {
                new_new_list.retain(|&a, _| a != [x,y]);
            }
            if total == 3 {
                new_new_list.insert([x,y], 0);
            }
            if total > 3 {         
                new_new_list.retain(|&a, _| a != [x,y]);
            }
            y += 1;
        }
        y = 0;
        x += 1;
    }
    
    new_new_list
}

struct MainState {
    alive_list: HashMap<[i32; 2], i32>,
}

impl MainState {
    fn new() -> ggez::GameResult<MainState> {
        let s = MainState {
            alive_list: alive_gen(),
        };
        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut ggez::Context) -> ggez::GameResult {
        self.alive_list = count_neighbors(self.alive_list.clone());

        Ok(())
    }

    fn draw(&mut self, ctx: &mut ggez::Context) -> ggez::GameResult {
        graphics::clear(ctx, graphics::WHITE);
        
        for arr in self.alive_list.clone() {
            let x = arr.0[0];
            let y = arr.0[1];

            let rekt = graphics::Mesh::new_rectangle(
                ctx,
                graphics::DrawMode::fill(),
                graphics::Rect::new((x * 10) as f32, (y * 10) as f32, WIDTH / GRID_X, WIDTH / GRID_Y),
                graphics::BLACK,
            )?;
            graphics::draw(ctx, &rekt, (na::Point2::new(0.0, 0.0),))?;
        }
        
        graphics::present(ctx)?;
        sleep(time::Duration::from_millis(100));
        Ok(())
    }
}

pub fn main() -> ggez::GameResult {
    let cb = ggez::ContextBuilder::new("bruh", "/dev/shm").window_mode(ggez::conf::WindowMode {
        width: WIDTH,
        height: HEIGHT,
        maximized: false,
        fullscreen_type: ggez::conf::FullscreenType::Windowed,
        borderless: false,
        min_width: 0.0,
        max_width: 0.0,
        min_height: 0.0,
        max_height: 0.0,
        resizable: false,
    });
    let (ctx, event_loop) = &mut cb.build()?;
    let state = &mut MainState::new()?;
    event::run(ctx, event_loop, state)
}
